package com.nulldev.util.crypto.api2.encryptors;

import java.nio.charset.Charset;
import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import com.nulldev.util.crypto.api2.Cryptable;
import com.nulldev.util.java.JVMUtil;
import com.nulldev.util.other.CharsetUtil;

public class Blowfish extends Cryptable{

	public Blowfish() {
		super("Blowfish");
	}

	@Override
	public String encrypt(String object, String pass) {
		try {
			//if (pass.length() % 8 != 0 || pass.length() > Cipher.getMaxAllowedKeyLength("Blowfish")) {
			//	throw new RuntimeException("Password is not an interval of 8 or is too large. Got '" + pass.length() + "'.");
			//}
		    Key aesKey = new SecretKeySpec(pass.getBytes(CharsetUtil.getCharset()), "Blowfish");
		    Cipher cipher = Cipher.getInstance("Blowfish");
		    cipher.init(Cipher.ENCRYPT_MODE, aesKey);
		    final String out = toHexString(cipher.doFinal(object.getBytes()));
		    return out;
		}catch (Exception e) {
			e.printStackTrace();
			return object;
		}
	}

	@Override
	public String decrypt(String object, String pass) {
		try {
			//if (pass.length() % 8 != 0 || pass.length() > Cipher.getMaxAllowedKeyLength("Blowfish")) {
			//	throw new RuntimeException("Password is not an interval of 8 or is too large. Got '" + pass.length() + "'.");
			//}
		    Key aesKey = new SecretKeySpec(pass.getBytes(CharsetUtil.getCharset()), "Blowfish");
		    Cipher cipher = Cipher.getInstance("Blowfish");
		    cipher.init(Cipher.DECRYPT_MODE, aesKey);
		    return new String(cipher.doFinal(toByteArray(object)));
		}catch (Exception e) {
			if (!e.getMessage().equals("Input length must be multiple of 8 when decrypting with padded cipher")) {
				System.err.println(JVMUtil.fromError(e));
			}
			throw new UnsupportedOperationException(e);
		}
	}
	
	@Override
	public String encrypt(String object, String pass, Charset charset) {
		try {
			//if (pass.length() % 8 != 0 || pass.length() > Cipher.getMaxAllowedKeyLength("Blowfish")) {
			//	throw new RuntimeException("Password is not an interval of 8 or is too large. Got '" + pass.length() + "'.");
			//}
		    Key aesKey = new SecretKeySpec(pass.getBytes(CharsetUtil.getCharset()), "Blowfish");
		    Cipher cipher = Cipher.getInstance("Blowfish");
		    cipher.init(Cipher.ENCRYPT_MODE, aesKey);
		    if (charset == null) {
			    final String out = toHexString(cipher.doFinal(object.getBytes()));
			    return out;
		    }else {
			    final String out = toHexString(cipher.doFinal(object.getBytes(charset)));
			    return out;
		    }
		}catch (Exception e) {
			e.printStackTrace();
			return object;
		}
	}

	@Override
	public String decrypt(String object, String pass, Charset charset) {
		try {
			//if (pass.length() % 8 != 0 || pass.length() > Cipher.getMaxAllowedKeyLength("Blowfish")) {
			//	throw new RuntimeException("Password is not an interval of 8 or is too large. Got '" + pass.length() + "'.");
			//}
		    Key aesKey = new SecretKeySpec(pass.getBytes(CharsetUtil.getCharset()), "Blowfish");
		    Cipher cipher = Cipher.getInstance("Blowfish");
		    cipher.init(Cipher.DECRYPT_MODE, aesKey);
		    if (charset == null) {
		    	return new String(cipher.doFinal(toByteArray(object)));
		    }else {
		    	return new String(cipher.doFinal(toByteArray(object)), charset);
		    }
		}catch (Exception e) {
			if (!e.getMessage().equals("Input length must be multiple of 8 when decrypting with padded cipher")) {
				System.err.println(JVMUtil.fromError(e));
			}
			return object;
		}
	}

    public static String toHexString(byte[] bytes) {
    	StringBuilder sb = new StringBuilder();
     	for (byte b : bytes) {
     		sb.append(String.format("%02X", b));
     	}
     	return sb.toString();
    }

    public static byte[] toByteArray(String s) {
    	int len = s.length();
     	byte[] data = new byte[len / 2];
     	for (int i = 0; i < len; i += 2) {
     		try {
     			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
     		}catch (Exception e) {}
     	}
     	return data;
    }
}
